//
//  NSObject+UnRecognizedSelHandler.m
//  SpaceHome
//
//  Created by ccSunday on 2017/3/23.
//
//

#import "NSObject+UnRecognizedSelHandler.h"
#import <objc/runtime.h>
#import <Photos/PHPhotoLibrary.h>
#import "fishhook.h"
#import "MOXLogUntil.h"
#import "QACommonUtils.h"
//#import "AppDelegate.h"

//提示框--->UIAlertController
#define ALERT_VIEW(Title,Message,Controller) {UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil];UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:Title message:Message preferredStyle:UIAlertControllerStyleAlert];        [alertVc addAction:action];[Controller presentViewController:alertVc animated:YES completion:nil];}

static NSString *_errorFunctionName;
void dynamicMethodIMP(id self,SEL _cmd){
    NSString *error = [NSString stringWithFormat:@"class->%@\n fuction->%@\n reason->调用无法识别方法",NSStringFromClass([self class]),_errorFunctionName];

#ifdef DEBUG
//
//    NSArray *syms = [NSThread  callStackSymbols];
//    NSString *fileAndMethod;
//    for (NSString *str in syms) {
//        if ([str containsString:@"["] && [str containsString:@"]"] && ![str containsString:@"dynamicMethodIMP"]) {
//            fileAndMethod = [NSString interceptionWithResourceString:str start:@"[" end:@"]"];
//            break;
//        }
//    }
//
//    NSLog(@"method = %@",fileAndMethod);
    dispatch_async(dispatch_get_main_queue(), ^{

        if (![self respondsToSelector:NSSelectorFromString(_errorFunctionName)]) {
            UIViewController *currentRootViewController = [self topViewControllerForKeyWindow];
            ALERT_VIEW(@"程序异常",error,currentRootViewController);
        }
    });
    NSLog(@"程序异常：%@", error);
#else
    [MOXLogUntil LogWarningWithString:@"------------------------------程序异常：%@", error];

#endif
    
}
#pragma mark 方法调换
static inline void change_method(Class _originalClass ,SEL _originalSel,Class _newClass ,SEL _newSel){
    Method methodOriginal = class_getInstanceMethod(_originalClass, _originalSel);
    Method methodNew = class_getInstanceMethod(_newClass, _newSel);
    method_exchangeImplementations(methodOriginal, methodNew);
}



@implementation NSObject (UnRecognizedSelHandler)
+ (void)load{
    
    // 实现交换
    change_method([self class], @selector(methodSignatureForSelector:), [self class], @selector(SH_methodSignatureForSelector:));
    
    change_method([self class], @selector(forwardInvocation:), [self class], @selector(SH_forwardInvocation:));
    
        
    int maxCrash = [GETUserDefaultsForKey(@"mo_maxCrash") intValue];//监听启动崩溃，暂时只为测试修复 rebind_symbols
    maxCrash ++;
    SETUserDefaults(@(maxCrash), @"mo_maxCrash");
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        SETUserDefaults(@(0), @"mo_maxCrash");
    });

    
    BOOL needRebind = YES;
    if (maxCrash > 1) {
        needRebind = NO;
        SETUserDefaults(@(YES), @"dontRebind");
    } else {
        BOOL saveNeedRebind = [GETUserDefaultsForKey(@"dontRebind") boolValue];
        if (saveNeedRebind) {//崩溃过的就不再交换
            needRebind = NO;
        }
    }
//    MO_Update
//    if (@available(iOS 15, *)) {
//        if ([[MOModuleService getDeviceInfo] isEqualToString:@"iPhone X"]) {
//            needRebind = NO;
//        }
//    }
    
    if (needRebind) {
        PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
        BOOL hook = NO;
        if (@available(iOS 14, *)) {
            if (status == PHAuthorizationStatusLimited) {
                hook = YES;
            }
        } else {
            // Fallback on earlier versions
        }

        if (status == 3) {
            hook = YES;
        }
        
        if (hook) {
            UIImageWriteToSavedPhotosAlbum(nil, nil, nil, nil);
        }

        @try {
            // rebinding 结构体
            struct rebinding whiteImageToAlbum;
            whiteImageToAlbum.name = "UIImageWriteToSavedPhotosAlbum";
            whiteImageToAlbum.replacement = MOImageWriteToSavedPhotosAlbum;
            whiteImageToAlbum.replaced = (void**)&oldWriteToAlbum;

            struct rebinding rebs[1] = {whiteImageToAlbum};
            // 用来重新绑定符号,可以一次交换多个
            // arg1: 存放rebinding结构体的数组
            // arg2: 数组的长度
            rebind_symbols(rebs, 1);
            
        } @catch (NSException *exception) {
            SETUserDefaults(exception, @"rebindCrashSave");
        } @finally {
            
        }
    }
}



//// 函数指针，保存原始的函数地址
//
static void(*oldWriteToAlbum)(UIImage *image, __nullable id completionTarget, __nullable SEL completionSelector, void * __nullable contextInfo);

// 定义一个新的函数
void MOImageWriteToSavedPhotosAlbum(UIImage *image, __nullable id completionTarget, __nullable SEL completionSelector, void * __nullable contextInfo) {

//    [MOXLogUntil LogWarningWithString:@"save image to album completionTarget = %@",completionTarget];
//    [MOXLogUntil LogWarningWithString:@"%@",[NSThread callStackSymbols]];
    if (completionTarget) {
        if (![completionTarget isKindOfClass:UIImageView.class]) {
//            oldWriteToAlbum(image,completionTarget,completionSelector,contextInfo);
        }
    }
    //MO_Update
//    [MOModuleService buglyReportName:@"MOImageWriteToSavedPhotosAlbum"
//                              reason:@"存储照片"
//                           extraInfo:@{@"completionTarget":completionTarget,@"completionSelector":NSStringFromSelector(completionSelector)}];
}



- (NSMethodSignature *)SH_methodSignatureForSelector:(SEL)aSelector {
    if ([self isKindOfClass:NSClassFromString(@"SKInvocationQueueProxy")]) {
          return [self SH_methodSignatureForSelector:aSelector];
    }
    if (![self respondsToSelector:aSelector]) {
        _errorFunctionName = NSStringFromSelector(aSelector);
        NSMethodSignature *methodSignature = [self SH_methodSignatureForSelector:aSelector];
        if (class_addMethod([self class], aSelector, (IMP)dynamicMethodIMP, "v@:")) {//方法参数的获取存在问题
            NSLog(@"临时方法添加成功！");
            NSArray *syms = [NSThread callStackSymbols];
            dispatch_async(dispatch_get_main_queue(), ^{
//                NSString *fileAndMethod;
//                for (NSString *str in syms) {
//                    if ([str containsString:@"["] && [str containsString:@"]"] && [str containsString:NSStringFromClass([MOToast getCurrentShowViewController].class)]) {
//                        fileAndMethod =  str;//[NSString interceptionWithResourceString:str start:@"[" end:@"]"];
//                        break;
//                    }
//                }
//
//                NSString * errS = [NSString stringWithFormat:@"!!!!!!!!!!!!!!!!!!!!!!!! ----self class: %@----selector:%@ --------\n---vcname = %@ ---method%@-------------------!!!!!!!!!!!!!!!",NSStringFromClass(self.class),_errorFunctionName,NSStringFromClass([MOToast getCurrentShowViewController].class),fileAndMethod];

                NSString * errS = [NSString stringWithFormat:@"!!!!!!!!!!!!!!!!!!!!!!!! ----self class: %@ ---- selector:%@ --------\n---vcname = %@  -------------!!!!!!!!!!!!!!!",NSStringFromClass(self.class),_errorFunctionName,NSStringFromClass([QACommonUtils getCurrentShowViewController].class)];
//
                [MOXLogUntil LogWarningWithString:@"[selecotor error]%@", errS];
                [QAModuleService buglyReportName:@"SH_methodSignatureForSelector" reason:@"方法错误，添加临时方法" extraInfo:@{@"err":errS,@"stack":syms,@"stackString":[syms yy_modelToJSONString]}];
            });
        }
        if (!methodSignature) {
            methodSignature = [self SH_methodSignatureForSelector:aSelector];
        }
        
        return methodSignature;
        
    }else{
        return [self SH_methodSignatureForSelector:aSelector];
    }
}

- (void)SH_forwardInvocation:(NSInvocation *)anInvocation{
    SEL selector = [anInvocation selector];
    if ([self respondsToSelector:selector]) {
        [anInvocation invokeWithTarget:self];
    }else{
        [self SH_forwardInvocation:anInvocation];
    }
}
@end
